﻿using UnityEngine;
// ReSharper disable InconsistentNaming

namespace Core
{
    public abstract class AbstractWindow : Component, IAwake<TblWnd.Conf>, IWindow
    {
        public bool Active { get; protected set; }
        public TblWnd.Conf Conf { get; protected set; }
        public GameObject gameObject { get; protected set; }
        public Transform transform { get; protected set; }

        public RectTransform rootRect { get; protected set; }

        public Canvas canvas { get; protected set; }
        public CanvasGroup canvasGroup { get; protected set; }

        protected bool IsInited;

        public virtual void Awake(TblWnd.Conf conf)
        {
            Conf = conf;
            Active = false;
            IsInited = false;
        }

        public override void Dispose()
        {
            if (IsDisposed) return;

            OnDestroy();

            G.UI.DisposeUIField(this);

            Active = false;
            IsInited = false;
            Conf = null;

            rootRect = null;
            transform = null;
            Utils.Trans.DestroyImmediate(gameObject);
            gameObject = null;

            base.Dispose();
        }

        public virtual void Show()
        {
            if (IsInited == false)
            {
                Init(1);
            }
            else
            {
                G.UI.RefreshOrientation(this);
                Active = true;
                Utils.Trans.SetActive(gameObject, true);
                transform.SetAsLastSibling();

                OnShow();
                G.UI.OnShow?.Invoke(Conf.Id);
            }
        }

        public virtual void Close()
        {
            if (IsInited == false)
            {
                Init(2);
            }
            else
            {
                OnClose();

                Active = false;
                Utils.Trans.SetActive(gameObject, false);

                G.UI.OnClose?.Invoke(Conf.Id);
            }
        }

        protected int m_ready2_flag = 0;
        protected async void Init(int flag)
        {
            if (m_ready2_flag != 0)
            {
                m_ready2_flag = flag;
                return;
            }
            m_ready2_flag = flag;

            var asset = await G.Res.LoadAsync(Conf.ResPath);
            var layer = G.UI.Get(Conf.Layer);
            var go = GameObject.Instantiate(asset.Obj, layer.Transform) as GameObject;
            go.SetLayer(layer.GameObject.layer);

            gameObject = go;
            transform = go.transform;

            var root = transform.Find("root");
            if (root != null)
            {
                rootRect = root.GetComponent<RectTransform>();
            }
            RefreshSafeArea();

            canvas = layer.Canvas;
            canvasGroup = go.GetComponent<CanvasGroup>();
            if (canvasGroup != null)
            {
                canvasGroup.blocksRaycasts = G.UI.BlocksRaycasts;
            }
            G.UI.ParseUIField(this, gameObject);

            IsInited = true;

            OnInit();

            if (m_ready2_flag == 1)
            {
                Show();
            }
            else if (m_ready2_flag == 2)
            {
                Close();
            }
            m_ready2_flag = 0;
        }

        protected virtual void OnInit() { }
        protected virtual void OnShow() { }
        protected virtual void OnClose() { }
        protected virtual void OnDestroy() { }

        private void RefreshSafeArea()
        {
            if (rootRect == null) return;

            var safeArea = S.Setting.Screen.SafeArea;
            var size = S.Setting.Screen.Size;

            //log.err($"window.safearea={safeArea}");
            //log.err($"window.size={size}");

            var min_x = safeArea.x / size.Width;
            var min_y = safeArea.y > 0 ? 0.02f : 0f;
            var max_x = 1 - (size.Width - safeArea.width - safeArea.x) / size.Width;
            var max_y = 1 - (size.Height - safeArea.height - safeArea.y) / size.Height;

            //log.err($"window.anchor min=({min_x},{min_y})");
            //log.err($"window.anchor max=({max_x},{max_y})");

            rootRect.anchorMin = new Vector2(min_x, min_y);
            rootRect.anchorMax = new Vector2(max_x, max_y);
        }
    }
}
